package com.hans.scala

// 有理数类
class Rational(n: Int, d: Int) {
  println("init Rational class.")

  //在构造对象时确保分母不为零
  require(d != 0)


  // 获得分子分母的最大公约数
  private val g = gcd(n.abs, d.abs)
  // 分子
  val numer: Int = n / g
  // 分母
  val denom: Int = d / g

  // 重载构造器，此时的有理数实为整数
  def this(n: Int) = this(n, 1)

  def this(n: Int, d: Int, mem: String) = {
    this(n, d)
    println(mem)
  }

  // 重写toString，必须加上override关键字
  override def toString =
    if (denom == 1) numer.toString else numer + "/" + denom

  // 常见的add方法
  def add(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)

  // 操作符形式的加法
  def +(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)

  def +(i: Int): Rational = new Rational(numer + i * denom, denom)

  def *(that: Rational): Rational = new Rational(numer * that.numer, denom * that.denom)

  def *(i: Int): Rational = new Rational(numer * i, denom)

  def -(that: Rational): Rational = new Rational(numer * that.denom - that.numer * denom, denom * that.denom)

  def -(i: Int): Rational = new Rational(numer - i * denom, denom)

  def /(that: Rational): Rational = new Rational(numer * that.denom, that.numer * denom)

  // 求倒数的前缀操作符，必须加上unary_修饰~
  def unary_~(that: Rational): Rational = new Rational(denom, numer)

  // 求两数中的较大数
  def max(that: Rational): Rational =
  //if(lessThan(that)) that else this //省略this也可以
    if (this lessThan that) that else this

  // 有理数的比较：小于
  def lessThan(that: Rational) =
    numer * that.denom < that.numer * denom

  // 递归求分子分母的最大公约数，必须指明结果类型
  private def gcd(a: Int, b: Int): Int =
    if (b == 0) a else gcd(b, a % b)
}

object Rational {
  def apply(n: Int, d: Int) = new Rational(n, d)

  def unapply(f: Rational) =
    if (f.denom == 0) None else Some((f.numer, f.denom))

  def apply(n: Int, d: Int, mem: String) = new Rational(n, d, mem)
}

object RationalTest {
  def main(args: Array[String]) {
    //    new Rational(5, 0)//requirement failed exception

    //    val t = new Rational(5, 2, "this is 5/2")
    val t = Rational(5, 2, "this is 5/2")

    // val r = new Rational(2, 3)
    val r = Rational(2, 3)

    println(r * 5)
    println(r * r)

    //隐身转换
    //动态给一个类添加一个方法
    implicit def intToRational(x: Int) = new Rational(x)

    println(5 * r)

    val num = 4 * 5
    println(num)

    //unapply  提取器
    Rational.unapply(Rational(2, 3))
    val Rational(n, d) = Rational(2, 3) //unapply
    println(n + " " + d)
  }
}

